package based

import (
	"github.com/syndtr/goleveldb/leveldb"
	"strconv"
	"strings"
	//"fmt"
	"github.com/Doresimon/SM-Collection/SM3"
	"fmt"
)
var Sdb_Pre, _ = leveldb.OpenFile("./db/Prescription.db", nil)
var Sdb_Map, _ = leveldb.OpenFile("./db/Mapping.db", nil)
var Sdb_TX, _ 	= leveldb.OpenFile("./db/Transaction.db", nil)
var Sdb_Buy, _ 	= leveldb.OpenFile("./db/Buy.db", nil)
var Sdb_Dose, _ 	= leveldb.OpenFile("./db/Dose.db", nil)
var Sdb_Block, _ = leveldb.OpenFile("./db/BlockChain.db", nil)

//存储处方，输入一个处方
func PutPrescription(a Presciption) {
	// db, err := leveldb.OpenFile("./db/Prescription.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return
	// }
	// db2, err := leveldb.OpenFile("./db/Mapping.db", nil)
	// defer Sdb_Map.Close()
	// if err != nil {
	// 	return
	// }

	aserial := a.serialize()
	err := Sdb_Pre.Put([]byte(a.Presciption_id), aserial, nil)
	if err != nil {
		return
	}

	//病人
	data, err := Sdb_Map.Get([]byte(a.Patient_id), nil)
	if err != nil {
		preids := a.Presciption_id
		err = Sdb_Map.Put([]byte(a.Patient_id), []byte(preids), nil)
		if err != nil {
			return
		}
	} else {
		plus := "," + a.Presciption_id
		data = append(data, []byte(plus)...)
		err = Sdb_Map.Put([]byte(a.Patient_id), data, nil)
		if err != nil {
			return
		}
	}

	//医院
	data, err = Sdb_Map.Get([]byte(a.Hospital_id), nil)
	if err != nil {
		preids := a.Presciption_id
		err = Sdb_Map.Put([]byte(a.Hospital_id), []byte(preids), nil)
		if err != nil {
			return
		}
	} else {
		plus := "," + a.Presciption_id
		data = append(data, []byte(plus)...)
		err = Sdb_Map.Put([]byte(a.Hospital_id), data, nil)
		if err != nil {
			return
		}
	}


}

//存储药品，输入药品
func PutTransaction(a Transaction) {
	// db, err := leveldb.OpenFile("./db/Transaction.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return
	// }Sdb_TX

	aserial := a.serialize()

	last, err := Sdb_TX.Get([]byte("last"), nil)
	if err != nil {
		//病人id链接放置id
		err = Sdb_TX.Put([]byte(a.Patient_id), []byte("1"), nil)
		if err != nil {
			return
		}
		//放置id链接药方信息
		err = Sdb_TX.Put([]byte("1"), []byte(aserial), nil)
		if err != nil {
			return
		}
		//last链接最后的放置id
		err = Sdb_TX.Put([]byte("last"), []byte("1"), nil)
		if err != nil {
			return
		}
	} else {
		//last链接最后的放置id
		no, err := strconv.Atoi(string(last))
		if err != nil {
			return
		}
		plus := strconv.Itoa(no + 1)
		err = Sdb_TX.Put([]byte("last"), []byte(plus), nil)
		if err != nil {
			return
		}
		//放置id链接药方信息
		err = Sdb_TX.Put([]byte(plus), []byte(aserial), nil)
		if err != nil {
			return
		}
		//病人id链接放置id
		data, err := Sdb_TX.Get([]byte(a.Patient_id), nil)
		if err != nil {
			err = Sdb_TX.Put([]byte(a.Patient_id), []byte(plus), nil)
			if err != nil {
				return
			}
		} else {
			data = append(data, []byte(","+plus)...)
			err = Sdb_TX.Put([]byte(a.Patient_id), []byte(data), nil)
			if err != nil {
				return
			}
		}
	}

}

//存储病人购买信息
func PutBuy(a Buy) {
	// db, err := leveldb.OpenFile("./db/Buy.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return
	// }

	aserial := a.serialize()

	last, err := Sdb_Buy.Get([]byte("last"), nil)
	if err != nil {
		//病人id链接放置id
		err = Sdb_Buy.Put([]byte(a.Patient_id), []byte("1"), nil)
		if err != nil {
			return
		}
		//放置id链接买卖信息
		err = Sdb_Buy.Put([]byte("1"), []byte(aserial), nil)
		if err != nil {
			return
		}
		//last链接最后的放置id
		err = Sdb_Buy.Put([]byte("last"), []byte("1"), nil)
		if err != nil {
			return
		}
	} else {
		//last链接最后的放置id
		no, err := strconv.Atoi(string(last))
		if err != nil {
			return
		}
		plus := strconv.Itoa(no + 1)
		err = Sdb_Buy.Put([]byte("last"), []byte(plus), nil)
		if err != nil {
			return
		}
		//放置id链接买卖信息
		err = Sdb_Buy.Put([]byte(plus), []byte(aserial), nil)
		if err != nil {
			return
		}
		//病人id链接放置id
		data, err := Sdb_Buy.Get([]byte(a.Patient_id), nil)
		if err != nil {
			err = Sdb_Buy.Put([]byte(a.Patient_id), []byte(plus), nil)
			if err != nil {
				return
			}
		} else {
			data = append(data, []byte(","+plus)...)
			err = Sdb_Buy.Put([]byte(a.Patient_id), []byte(data), nil)
			if err != nil {
				return
			}
		}
	}

}

//存储剂量信息
func PutDose(a Dose) {
	//db, err := leveldb.OpenFile("./db/Dose.db", nil)
	//defer db.Close()
	//if err != nil {
	//	return
	//}

	aserial := a.serialize()
	last, err := Sdb_Dose.Get([]byte("last"), nil)
	if err != nil {
		//放置id链接剂量信息
		err = Sdb_Dose.Put([]byte("1"), []byte(aserial), nil)
		if err != nil {
			return
		}
		//last链接最后的放置id
		err = Sdb_Dose.Put([]byte("last"), []byte("1"), nil)
		if err != nil {
			return
		}
	} else {
		//last链接最后的放置id
		no, err := strconv.Atoi(string(last))
		if err != nil {
			return
		}
		plus := strconv.Itoa(no + 1)
		err = Sdb_Dose.Put([]byte("last"), []byte(plus), nil)
		if err != nil {
			return
		}
		//放置id链接剂量信息
		err = Sdb_Dose.Put([]byte(plus), []byte(aserial), nil)
		if err != nil {
			return
		}
	}
}

//药店判断自己是否已经发布tran
func IsPostdata(presciption_id string, site string, medicine_name string) bool {
	//db, err := leveldb.OpenFile("./db/Transaction.db", nil)
	//defer db.Close()
	//if err != nil {
	//	return false
	//}

	iter := Sdb_TX.NewIterator(nil, nil)
	for iter.Next() {
		if string(iter.Key())=="last" || len(iter.Key()) > 8 {
			continue
		}
		//fmt.Printf("%s\n",iter.Key())
		value := deserializeTransaction(iter.Value())
		if value.Data.Presciption_id == presciption_id && value.Data.Site == site && value.Data.Medicine_name == medicine_name{
			return true
		}
	}
	iter.Release()
	err := iter.Error()
	if err != nil {
		return false
	}
	return false
}

//获取剂量信息
func GetDosedata(medicine_name string, chemistry_name string, chemistry_amount int) (int,float32) {
	//一个剂量化学名对应的药品剂量
	var mamount int = 0
	//一剂量药品单价
	var mprice float32 = 0.0
	// db, err := leveldb.OpenFile("./db/Dose.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return 0,0.0
	// }

	iter := Sdb_Dose.NewIterator(nil, nil)
	for iter.Next() {
		if string(iter.Key()) == "last" {
			continue
		}
		value := deserializeDose(iter.Value())
		if value.Chemistry_name == chemistry_name && value.Medicine_name == medicine_name {
			mamount = value.Medicine_amount
			mprice = value.Medicine_price
			break
		}
	}
	iter.Release()
	err := iter.Error()
	if err != nil {
		return 0,0.0
	}

	return chemistry_amount * mamount, float32(chemistry_amount) * float32(mamount) * mprice
}

//根据病人ID查买卖信息
func GetBuyByid(patid string) []*Buy{
	var result []*Buy
	//
	// db, err := leveldb.OpenFile("./db/Buy.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return nil
	// }

	if patid != "*" {
		data, err := Sdb_Buy.Get([]byte(patid), nil)
		if err != nil {
			return nil
		}

		pres := strings.Split(string(data), ",")
		for _, pre := range pres {
			re, err := Sdb_Buy.Get([]byte(pre), nil)
			//fmt.Printf("%s\n",re)
			if err != nil {
				return nil
			}

			result = append(result, deserializeBuy(re))
		}
	}else { //监管部门使用
		iter := Sdb_Buy.NewIterator(nil, nil)
		for iter.Next() {
			if string(iter.Key())=="last" || len(iter.Key()) > 8 {
				continue
			}
			value := deserializeBuy(iter.Value())
			result = append(result, value)
		}
		iter.Release()
		err := iter.Error()
		if err != nil {
			return nil
		}
	}
	return result
}

//根据病人ID或者医院ID查相关处方信息
func GetPrescriptionByid(id string) []*Presciption {
	var result []*Presciption

	// db, err := leveldb.OpenFile("./db/Prescription.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return nil
	// }
	// db2, err := leveldb.OpenFile("./db/Mapping.db", nil)
	// defer Sdb_Map.Close()
	// if err != nil {
	// 	return nil
	// }

	if id != "*" {
		data, err := Sdb_Map.Get([]byte(id), nil)
		if err != nil {
			return nil
		}

		pres := strings.Split(string(data), ",")
		for _, pre := range pres {
			re, err := Sdb_Pre.Get([]byte(pre), nil)
			//fmt.Printf("%s\n",re)
			if err != nil {
				return nil
			}

			result = append(result, deserializePrescription(re))
		}
	}else {
		iter := Sdb_Pre.NewIterator(nil, nil)
		for iter.Next() {
			value := deserializePrescription(iter.Value())
			result = append(result, value)
		}
		iter.Release()
		err := iter.Error()
		if err != nil {
			return nil
		}
	}

	return result
}

//根据详细处方ID查相关处方信息
func GetPrescriptionBypreid(preid string) *Presciption {
	// db, err := leveldb.OpenFile("./db/Prescription.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return nil
	// }

	data, err := Sdb_Pre.Get([]byte(preid), nil)
	if err != nil {
		return nil
	}

	return deserializePrescription(data)
}

//根据简略处方ID查相关药品信息
func GetPrescriptionByeasypreid(easypreid string) []*Transaction {
	var result []*Transaction
	var temp []string

	// db, err := leveldb.OpenFile("./db/Prescription.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return nil
	// }
	//
	// db2, err := leveldb.OpenFile("./db/Transaction.db", nil)
	// defer Sdb_TX.Close()
	// if err != nil {
	// 	return nil
	// }

	iter := Sdb_Pre.NewIterator(nil, nil)
	for iter.Next() {
		value := deserializePrescription(iter.Value())
		if value.Presciption_id[:16] == easypreid {
			temp = append(temp, value.Presciption_id)
		}
	}
	iter.Release()
	err := iter.Error()
	if err != nil {
		return nil
	}

	iter = Sdb_TX.NewIterator(nil, nil)
	for iter.Next() {
		if string(iter.Key())=="last" || len(iter.Key()) > 8 {
			continue
		}
		value := deserializeTransaction(iter.Value())
		if isexist(temp, value.Data.Presciption_id) {
			result = append(result, value)
		}
	}
	iter.Release()
	err = iter.Error()
	if err != nil {
		return nil
	}

	return result
}

//根据病人ID查相关药品信息
func GetTransactionByid(id string) []*Transaction {
	var result []*Transaction

	// db, err := leveldb.OpenFile("./db/Transaction.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return nil
	// }

	if id != "*" {
		data, err := Sdb_TX.Get([]byte(id), nil)
		if err != nil {
			return nil
		}

		pres := strings.Split(string(data), ",")
		for _, pre := range pres {
			re, err := Sdb_TX.Get([]byte(pre), nil)
			//fmt.Printf("%s\n",re)
			if err != nil {
				return nil
			}

			result = append(result, deserializeTransaction(re))
		}
	}else {
		iter := Sdb_TX.NewIterator(nil, nil)
		for iter.Next() {
			if string(iter.Key())=="last" || len(iter.Key()) > 8 {
				continue
			}
			value := deserializeTransaction(iter.Value())
			result = append(result, value)
		}
		iter.Release()
		err := iter.Error()
		if err != nil {
			return nil
		}
	}

	return result
}

//输入处方id，将对应处方设置成已处理                ////////////////废弃

//func Update(presciption_id string) {
//	db, err := leveldb.OpenFile("./db/Prescription.db", nil)
//	if err != nil {
//		return
//	}
//
//	iter := db.NewIterator(nil, nil)
//	for iter.Next() {
//		value := deserializePrescription(iter.Value())
//		if value.Presciption_id == presciption_id {
//			value.Ishandled = true
//			err = db.Put([]byte(presciption_id), value.serialize(), nil)
//			if err != nil {
//				return
//			}
//			break
//		}
//	}
//	iter.Release()
//	err = iter.Error()
//	if err != nil {
//		return
//	}
//
//	defer db.Close()
//}

//根据药店属性获取对应处方
func GetPrescriptionByattr(attr []string) []*Presciption {
	var result []*Presciption

	// db, err := leveldb.OpenFile("./db/Prescription.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return nil
	// }

	iter := Sdb_Pre.NewIterator(nil, nil)
	for iter.Next() {
		value := deserializePrescription(iter.Value())
		if match(attr, value.Policy) {
			result = append(result, value)
		}
	}
	iter.Release()
	err := iter.Error()
	if err != nil {
		return nil
	}

	return result
}

//根据处方id/药店名/药品名获取买卖信息是否存在,site和medicine_name输入*为不用
func IsBuy(presciption_id string, site string, medicine_name string) bool {
	// db, err := leveldb.OpenFile("./db/Buy.db", nil)
	// defer db.Close()
	// if err != nil {
	// 	return false
	// }

	iter := Sdb_Buy.NewIterator(nil, nil)
	for iter.Next() {
		if string(iter.Key()) == "last" || len(iter.Key()) > 8 {
			continue
		}
		//fmt.Printf("%s\n",iter.Key())
		value := deserializeBuy(iter.Value())
		if value.Data.Presciption_id == presciption_id && (value.Data.Site == site || site == "*") && (value.Data.Medicine_name == medicine_name || medicine_name == "*") {
			return true
		}
	}
	iter.Release()
	err := iter.Error()
	if err != nil {
		return false
	}
	return false

}

//Block结构
func putBlock(a Block){
	aserial := a.serialize()
	err := Sdb_Block.Put([]byte(strconv.Itoa(a.Height)), aserial, nil)
	if err != nil {
		return
	}
	err = Sdb_Block.Put([]byte("last"), []byte(strconv.Itoa(a.Height)), nil)
	if err != nil {
		return
	}
	fmt.Println(a.Height)
	fmt.Println(a.DataHash)
	fmt.Println(a.PrevHash)
	fmt.Println(a.ThisHash)
	fmt.Println(a.Ts)
}

//获得block
func GetBlock() []*Block{
	var result = []*Block{}
	iter := Sdb_Block.NewIterator(nil, nil)
	for iter.Next() {
		if string(iter.Key()) == "last" {
			continue
		}

		value := deserializeBlock(iter.Value())
		result = append(result, value)
	}
	iter.Release()
	err := iter.Error()
	if err != nil {
		return nil
	}
	return result
}

func getOneMinuteBeforeHash(ts uint64) []byte{
	var result = []byte{}
	iter := Sdb_Pre.NewIterator(nil, nil)
	for iter.Next() {
		value := deserializePrescription(iter.Value())
		if ts - value.Ts >= 60 && ts - value.Ts < 120 {
			result = append(result, iter.Value()...)
		}
	}
	iter.Release()
	err := iter.Error()
	if err != nil {
		return nil
	}

	iter = Sdb_TX.NewIterator(nil, nil)
	for iter.Next() {
		if string(iter.Key()) == "last" || len(iter.Key()) > 8 {
			continue
		}
		value := deserializeTransaction(iter.Value())
		if ts - value.Data.Ts >= 60 && ts - value.Data.Ts < 120 {
			result = append(result, iter.Value()...)
		}
	}
	iter.Release()
	err = iter.Error()
	if err != nil {
		return nil
	}

	iter = Sdb_Buy.NewIterator(nil, nil)
	for iter.Next() {
		if string(iter.Key()) == "last" || len(iter.Key()) > 8 {
			continue
		}
		value := deserializeBuy(iter.Value())
		if ts - value.Data.Ts >= 60 && ts - value.Data.Ts < 120 {
			result = append(result, iter.Value()...)
		}
	}
	iter.Release()
	err = iter.Error()
	if err != nil {
		return nil
	}

	return SM3.SM3_256(result)
}

func getBlockHash(height int) []byte{
	if height == 0 {
		return []byte("")
	}
	data, err := Sdb_Block.Get([]byte(strconv.Itoa(height)), nil)
	if err != nil {
		return nil
	}
	block := deserializeBlock(data)
	return counthash(block.DataHash, block.PrevHash, block.Ts, block.Height)
}

func getLastBlockHeight() int{
	data, err := Sdb_Block.Get([]byte("last"), nil)
	if err != nil {
		return 0
	}
	height, err := strconv.Atoi(string(data))
	if err != nil {
		return 0
	}
	return height
}